module WallaceMultiplier #(
    parameter WIDTH = 64,
    parameter E = WIDTH + 2,
    parameter W = E * 2,
    parameter N = E / 2
) (
    input                       clock,
    input                       reset,
    input   logic [WIDTH-1:0]   x,
    input   logic [WIDTH-1:0]   y,
    input   logic [1:0]         signs,
    output  logic [2*WIDTH-1:0] result
);

    wire   [W-1:0] X = { {(WIDTH+4){signs[1] ? x[WIDTH-1] : 1'b0}}, x};
    wire   [W/2:0] Y = { { 2{signs[0] ? y[WIDTH-1] : 1'b0}}, y, 1'b0 };

/* ************ Partial Product ************ */ 
    generate
        for (genvar i = 0; i < N; i++) begin
            Radix4BoothProduct #(
                .WIDTH(W)
            ) booth (
                .y(Y[2*i+2:2*i]), 
                .x({X[W-1-(2*i):0], {(2*i){1'b0}}}), 
                .p(Pin[i]), 
                .c(Cin[i])
            );
        end
    endgenerate
/* ************ Partial Product ************ */ 

    logic [W-1:0]   Pin [N-1:0];
    logic [N-1:0]   Cin;
    logic [N-1:0]   Pout [W-1:0];
    logic [N-1:0]   Cout;

/* ************ Switch ************ */ 
    Switch #( .W(W) ) switch (
        .Pin(Pin),
        .Cin(Cin),
        .Pout(Pout),
        .Cout(Cout)
    );
/* ************ Switch ************ */ 
    /* verilator lint_off UNUSEDSIGNAL */
    logic [W-1:0]   WS, WC;
    logic [25:00]   WCout0 [W-1:0];
    logic [35:26]   WCout1 [W-1:0];

/* ************ WallaceTree ************ */
    wire [35:0] WCin = {3'h0, Cout};
    logic [35:0] WCinR;
    always_ff @(posedge clock) begin : SplitPipeline
        if (reset) begin
            WCinR <= 36'h0;
        end 
        else begin
            WCinR <= WCin;
        end
    end
    WallaceTree33Bits wallace0 (
        .clock(clock),
        .reset(reset),
        .sin(Pout[0]), 
        .cin0(WCin[25:00]),
        .cin1(WCinR[35:26]),
        .cout0(WCout0[0][25:00]), 
        .cout1(WCout1[0][35:26]), 
        .s(WS[0]),
        .c(WC[0])
    );
    generate 
        for (genvar i = 1; i < W; i++) begin
            WallaceTree33Bits wallace (
                .clock(clock),
                .reset(reset),
                .sin(Pout[i]), 
                .cin0(WCout0[i-1][25:00]), 
                .cin1(WCout1[i-1][35:26]), 
                .cout0(WCout0[i][25:00]), 
                .cout1(WCout1[i][35:26]), 
                .s(WS[i]), 
                .c(WC[i])
            );
        end
    endgenerate
/* ************ WallaceTree ************ */ 

/* ****************** Adder ****************** */
    /* verilator lint_off UNUSEDSIGNAL */
    logic [W-1:0] FS;
    logic         FC;
    assign { FC, FS } = WS + {WC[W-2:0], 1'b0};
/* ****************** Adder ****************** */ 

    assign result = FS[2*WIDTH-1:0];
endmodule //BWM
